import { keyboardList } from '@/common/js/keyboard.js';
import useGameImgs from './useGameImgs.js';
import { computed, reactive, ref, watch, onBeforeUnmount } from 'vue';
import { saveComplete } from '@/common/api/course.js';
import useTyping from './useTyping.js';
const config = {
	spawnIntervals: 1200, //生成间隔时间
	itemSpeed: 0.1, //下降速度
	itemSize: 50, //字母背景大小
	itemColor: '#fff', //字母颜色
	itemFontSize: 36, //字母字体大小
	itemSpacing: 30, //左右间隔
	planeItemSpacing: 126, //中间大大飞机与左右两边的两个小飞机的距离
	explosionTime: 400, //爆炸时间
	explosionHeight: 120, //爆炸大小
	bulletHeight: 60, //子弹大小
	bulletSpead: 0.5, //子弹速度
	maxHealth: 100, //最大血量
	danageHealth: 5, //每次按键错误扣血量
	danageHealthExplosion: 25, //每次和飞机碰撞爆炸扣血量
	bgSpeed: 0.04, //背景滚动速度
	bgPlanetSpeed: 0.08, //背景上的球滚动速度
	planeBottom: 180, //飞机离底部距离-初始180 开始后100
	planeHeight: 130, //大飞机的高度
	smallPlaneHeight: 30, //小飞机的高度
	channelKeys: ['aqz', 'wsx', 'edc', 'rfvtgb', 'yhnujm', 'ikm', 'ol,', 'p;.'] //每列对应的字母
}
// 自适应调整
function resizePlaneParam(width) {
	const widthInit = 1500;
	const zoom_planeItemSpacing = config.planeItemSpacing / widthInit;
	const zoom_itemSpacing = config.itemSpacing / widthInit;
	const zoom_planeHeight = config.planeHeight / widthInit;
	const zoom_smallPlaneHeight = config.smallPlaneHeight / widthInit;
	const zoom_itemSize = config.itemSize / widthInit;
	const zoom_itemFontSize = config.itemFontSize / widthInit;
	config.planeItemSpacing = Math.round(zoom_planeItemSpacing * width);
	config.itemSpacing = Math.round(zoom_itemSpacing * width);
	config.planeHeight = Math.round(zoom_planeHeight * width);
	config.smallPlaneHeight = Math.round(zoom_smallPlaneHeight * width);
	config.itemSize = Math.round(zoom_itemSize * width);
	config.itemFontSize = Math.round(zoom_itemFontSize * width);
}
export default function(cont) {
	const { gameSound, stopSound } = useTyping();
	const gaming = reactive({
		step: 0, //4-结束
		result: {},
		health: config.maxHealth,
		keys: '',
		lastRenderTime: 0,
		channels: [],
		points: 0,
		currentIndex: 0,
		keyIndex: 0,
		nextSpawnTime: 0
	})
	let imageSource = {};
	// const { play, stop } = useSound();
	const width = document.body.clientWidth;
	const height = document.body.clientHeight;
	resizePlaneParam(width);
	let ctx = null;
	const requestAnimationIds = [];
	onBeforeUnmount(() => {
		clearGame();
	})
	// 键盘事件
	function keydownFun(e) {
		const find = keyboardList.find(item => item.keyCode == e.keyCode);
		if (find && find.key == ' ' && gaming.step == 1) {
			gaming.step++;
			gameSound('bgMusic', true);
			return startGame();
		}
		if (gaming.step != 2) return;
		const currentKey = gaming.keys[gaming.keyIndex];
		const findIndex = config.channelKeys.findIndex(key => key.includes(e.key));
		if (currentKey == e.key && findIndex > -1) {
			const channel = gaming.channels[findIndex];
			const item = channel.items[channel.bullets.length];
			if (item && item.key === e.key) {
				channel.bullets.push({
					key: e.key,
					y: height - config.planeBottom - config.smallPlaneHeight / 2 - config.planeHeight / 2 - config.bulletHeight / 2
				})
				gaming.keyIndex++;
			} else {
				danage();
			}
			gameSound('shoot');
		} else {
			danage();
			gameSound('shoot');
		}
	}
	// 进入第一步，准备开始
	function selectGame() {
		uni.showLoading({
			title: '加载中'
		})
		ctx = uni.createCanvasContext('canvas');
		const { loadComplete } = useGameImgs();
		watch(() => loadComplete.value, (newVal) => {
			// 资源加载完
			if (newVal) {
				imageSource = useGameImgs();
				// 保证图片资源的尺寸不为0
				setTimeout(() => {
					gaming.step = 1;
					uni.hideLoading();
					onReady();
				}, 20)
			}
		})
	}
	// 游戏开始前重置部分数据
	function initGame() {
		config.planeBottom = 180;
		gaming.result = {};
		gaming.health = config.maxHealth;
		gaming.channels = [];
		gaming.lastRenderTime = 0;
		gaming.nextSpawnTime = 0;
		gaming.currentIndex = 0;
		gaming.keyIndex = 0;
	}
	// 开始游戏，设置部分参数
	function startGame() {
		config.planeBottom = 100;
		gaming.channels.forEach((channel) => {
			channel.items = []
			channel.bullets = []
			channel.explosions = []
		})
	}
	// 初始化渲染
	function onReady() {
		initGame();
		// 添加左侧数据
		utils.fillChanelData(1);
		// 添加右侧数据
		utils.fillChanelData(-1);
		requestAnimationIds.push(requestAnimationFrame(render));
		document.onkeydown = keydownFun;
		utils.renderImage(imageSource.bulletImg, 0, 0, config.bulletHeight)
	}
	// 绘制
	function render(date) {
		requestAnimationIds.push(requestAnimationFrame(render));
		renderBG(date);
		renderBGPlanet(date);
		if ([1, 2].indexOf(gaming.step) > -1) {
			renderPlane();
		}
		if (gaming.step == 2) {
			renderGame(date);
			renderExplostion(date);
		}
		ctx.draw();
		gaming.lastRenderTime = date;
	}
	// 游戏开始绘制
	function renderGame(time) {
		if (gaming.nextSpawnTime < time && gaming.currentIndex !== gaming.keys.length) {
			const key = gaming.keys[gaming.currentIndex++];
			const channelIndex = config.channelKeys.findIndex(item => item.includes(key));
			gaming.channels[channelIndex].items.push({
				key,
				y: -config.itemSize,
			})
			gaming.nextSpawnTime = time + config.spawnIntervals;
		}
		const interval = time - gaming.lastRenderTime;
		for (const channel of gaming.channels) {
			const { items, bullets, explosions } = channel;
			items.forEach(item => item.y += interval * config.itemSpeed);
			bullets.forEach(bullet => bullet.y -= interval * config.bulletSpead);
			const planeTop = height - config.planeBottom - config.smallPlaneHeight * 2;
			// 检测飞机是否和字母相撞
			for (const item of items) {
				if (item.y >= planeTop - config.itemSize) {
					explosions.push({
						time,
						y: planeTop - imageSource.explosionFrams[0].naturalHeight + config.smallPlaneHeight,
					})
					danage(2);
					gameSound('explosion');
					items.shift();
					continue
				}
				break
			}
			// 子弹相关
			for (const bullet of bullets) {
				// 渲染子弹
				utils.renderImage(imageSource.bulletImg, bullet.y, channel.center, config.bulletHeight);
				// 检测子弹和下落物碰撞
				const fisrtItem = items[0];
				if (!fisrtItem) {
					break;
				}
				if (fisrtItem.y + config.itemSize > bullet.y) {
					if (fisrtItem.key !== bullet.key) {
						bullets.shift();
						danage();
						gameSound('explosion');
					} else {
						bullets.shift();
						items.shift();
						gaming.points++;
						gameSound('explosion');
					}
					explosions.push({
						time,
						y: bullet.y + (bullet.y - fisrtItem.y) / 2 - imageSource.explosionFrams[0].naturalHeight / 2
					})
					if (gaming.keyIndex == gaming.keys.length) {
						gameEnd('success');
					}
					continue;
				}
				break;
			}
			// 渲染字母
			for (const item of items) {
				utils.renderImage(imageSource.itemBgImg, item.y, channel.center, config.itemSize)
				const text = item.key.toLowerCase();
				const textSize = ctx.measureText(text);
				const left = channel.itemLeft + config.itemSize / 2 - textSize.width / 2;
				const top = item.y + config.itemSize / 2 + config.itemFontSize / 2 - 4;
				ctx.setFontSize(config.itemFontSize);
				ctx.fillStyle = config.itemColor;
				ctx.fillText(text, left, top);
			}
		}
	}
	// 渲染爆炸
	function renderExplostion(time) {
		for (const channel of gaming.channels) {
			channel.explosions.forEach((explosion, index) => {
				const range = config.explosionTime / imageSource.explosionFrams.length;
				const liveTime = time - explosion.time;
				const fram = Math.floor(liveTime / range);
				if (fram >= imageSource.explosionFrams.length) {
					channel.explosions.splice(index, 1);
					return
				}
				utils.renderImage(imageSource.explosionFrams[fram], explosion.y, channel.center, config.explosionHeight)
			})
		}
	}
	// 爆炸 1 - 按键 2 - 碰撞
	function danage(type = 1) {
		const reduce = type == 1 ? config.danageHealth : config.danageHealthExplosion;
		gaming.health = gaming.health - reduce;
		if (gaming.health <= 0) {
			gameEnd('fail');
		}
	}
	// 绘制背景
	let bgLocation = 0;

	function renderBG(time) {
		const zoom = width / imageSource.bgImg.naturalWidth;
		const renderHegiht = imageSource.bgImg.naturalHeight * zoom;
		ctx.drawImage(imageSource.bgImg.src, 0, (renderHegiht - height - bgLocation) / zoom, imageSource.bgImg.naturalWidth, height / zoom, 0, 0, width, height);
		const freeSpace = height - (renderHegiht - bgLocation);
		if (freeSpace > 0) {
			ctx.drawImage(imageSource.bgImg.src, 0, (renderHegiht - freeSpace) / zoom, imageSource.bgImg.naturalWidth, freeSpace / zoom, 0, 0, width, freeSpace);
		}
		bgLocation += (time - gaming.lastRenderTime) * config.bgSpeed;
		bgLocation %= renderHegiht;
	}
	// 绘制有星球的背景
	let bgPlanetLocation = 0

	function renderBGPlanet(time) {
		const zoom = width / imageSource.bgPlaneImg.naturalWidth;

		const renderHegiht = imageSource.bgPlaneImg.naturalHeight * zoom;

		ctx.drawImage(imageSource.bgPlaneImg.src, 0, (renderHegiht - height - bgPlanetLocation) / zoom, imageSource.bgPlaneImg.naturalWidth, height / zoom, 0, 0, width, height);

		const freeSpace = height - (renderHegiht - bgPlanetLocation);

		if (freeSpace > 0) {
			ctx.drawImage(imageSource.bgPlaneImg.src, 0, (renderHegiht - freeSpace) / zoom, imageSource.bgPlaneImg.naturalWidth, freeSpace / zoom, 0, 0, width, freeSpace);
		}
		bgPlanetLocation += (time - gaming.lastRenderTime) * config.bgPlanetSpeed;
		bgPlanetLocation %= imageSource.bgPlaneImg.naturalHeight * zoom;
	}
	// 绘制飞机
	function renderPlane() {
		// 绘制小飞机
		gaming.channels.forEach(item => {
			utils.renderImage(imageSource.rocketSmallImg, height - config.planeBottom - config.smallPlaneHeight / 2 - config.planeHeight / 2, item.center, config.smallPlaneHeight)
		})
		// 绘制大飞机
		utils.renderImage(imageSource.rocketImg, height - config.planeBottom - config.planeHeight, width / 2, config.planeHeight)
	}
	// 绘制工具
	const utils = {
		fillChanelData(unit) {
			for (let i = 0; i < 4; i++) {
				const center = width / 2 - config.planeItemSpacing * unit - i * config.itemSize * unit - i * config.itemSpacing * unit - (config.itemSize / 2) * unit;
				gaming.channels.push({
					center,
					itemLeft: center - config.itemSize / 2,
					items: [],
					bullets: [],
					explosions: [],
				})
			}
			gaming.channels.sort((a, b) => {
				return a.itemLeft - b.itemLeft;
			});
		},
		renderImage(image, top, center, height) {
			const zoom = height / image.naturalHeight;
			const width = zoom * image.naturalWidth;
			const left = center - width / 2;
			ctx.drawImage(image.src, left, top, width, height);
		}
	}
	// 清除游戏
	function clearGame() {
		// 清除canvas内容
		if (ctx) {
			ctx.clearRect(0, 0, width, height);
			ctx.draw();
		}
		requestAnimationIds.forEach(item => {
			cancelAnimationFrame(item);
		})
		ctx = null;
		document.onkeydown = null;
		initGame();
		stop();
	}
	// 游戏结束
	async function gameEnd(type) {
		ctx.clearRect(0, height - config.planeBottom - config.planeHeight, width, config.planeBottom + config.planeHeight);
		ctx.draw();
		if (type == 'success') {
			const characterId = getApp().globalData.dzcharacter?.character?.characterId;
			const { data } = await saveComplete({
				characterId,
				courseId: cont.courseId,
				health: Math.round(gaming.health / config.maxHealth * 100)
			})
		}
		gaming.step = 3;
		gaming.result.type = type;
	}
	return {
		gaming,
		selectGame,
		clearGame
	}
}